DETTEN CRACKME #6 ***************** Cracker: figugegl Email: figugegl_2000@yahoo.de Date: 20.10.2001 Tools: Softice, IDA Level 1-10: 5 A strange crackme with surprises! We see that the Register Button is greyed - we could easily patch this with a resource editor, but that's for newbies only (see info). Let's have a closer look at the imports: We see RegisterHotkey - interesting! We find this in the listing: 004012C7 6A 51 push 51h ; 'Q' 004012C9 6A 03 push 3 ; CTRL-ALT 004012CB 68 81 00 00 00 push 81h 004012D0 53 push ebx 004012D1 E8 F4 8B 00 00 call j_RegisterHotKey 004012D6 85 C0 test eax, eax 004012D8 0F 85 E3 00 00 00 jnz loc_4013C1 The API-Reference is very helpful in this case: BOOL RegisterHotKey ( HWND hWnd, // window to receive hot-key notification int id, // identifier of hot key UINT fsModifiers, // key-modifier flags: MOD_ALT, MOD_CONTROL, MOD_SHIFT UINT vk // virtual-key code ); To get the values of the parameter fsModifiers we have a look at the file Winuser.h of our C-Compiler: #define MOD_ALT 1 #define MOD_CONTROL 2 #define MOD_SHIFT 4 The hotkey is "Ctrl-Alt-Q". To see what's happening, we set a bpx GetDlgItemTextA, fill in our name and serial and"Ctrl-Alt-Q": 00401309 57 push edi 0040130A 56 push esi 0040130B 6A 65 push 65h 0040130D 53 push ebx 0040130E E8 A5 8B 00 00 call j_GetDlgItemTextA ; si pops up here: get name 00401313 56 push esi 00401314 E8 56 FE FF FF call sub_40116F ; call 1 00401319 59 pop ecx 0040131A 84 C0 test al, al ; test flag 0040131C 0F 84 9F 00 00 00 jz loc_4013C1 ; bad cracker jump 1 00401322 6A 01 push 1 00401324 68 C9 00 00 00 push 0C9h 00401329 53 push ebx 0040132A E8 7D 8B 00 00 call j_GetDlgItem 0040132F 50 push eax 00401330 E8 65 8B 00 00 call j_EnableWindow ; enable register button 00401335 56 push esi 00401336 E8 CD FD FF FF call sub_401108 ; call 2 0040133B 59 pop ecx 0040133C E9 80 00 00 00 jmp loc_4013C1 It gets our name and then executes call 1: 0040116F 55 push ebp 00401170 8B EC mov ebp, esp 00401172 53 push ebx 00401173 8B 55 08 mov edx, [ebp+arg_0] ; pointer to name (n) 00401176 33 C0 xor eax, eax 00401178 33 C9 xor ecx, ecx 0040117A EB 0E jmp short loc_40118A 0040117C 0F BE 1C 02 movsx ebx, byte ptr [edx+eax] ; loop start 00401180 D1 FB sar ebx, 1 ; n[i] >> 1 00401182 79 03 jns short loc_401187 ; jmp when positive 00401184 83 D3 00 adc ebx, 0 ; add with carry (when negative) 00401187 03 CB add ecx, ebx ; add (when positive) 00401189 40 inc eax 0040118A 80 3C 02 00 cmp byte ptr [edx+eax], 0 0040118E 75 EC jnz short loc_40117C ; loop end 00401190 3B 0D E8 A0 40 00 cmp ecx, dword_40A0E8 ; sum == 20Ah ? 00401196 75 05 jnz short loc_40119D 00401198 B0 01 mov al, 1 ; yes, set flag 0040119A 5B pop ebx 0040119B 5D pop ebp 0040119C C3 retn All characters of our name are shifted to the right and added. Note that they are signed characters. The sum must be 20Ah. Is this the case it enables the register button and executes the second call: 00401108 55 push ebp 00401109 8B EC mov ebp, esp 0040110B 83 C4 F8 add esp, 0FFFFFFF8h 0040110E 53 push ebx 0040110F 57 push edi 00401110 C7 45 FC 37 12 40+ mov [ebp+var_4], offset loc_401237 00401117 8D 45 F8 lea eax, [ebp+var_8] 0040111A 50 push eax 0040111B 6A 04 push 4 0040111D 6A 33 push 33h 0040111F FF 75 FC push [ebp+var_4] 00401122 E8 5B 8D 00 00 call j_VirtualProtect 00401127 52 push edx 00401128 57 push edi 00401129 50 push eax 0040112A 8B 7D FC mov edi, [ebp+var_4] ; pointer to addresse 401237 (c) 0040112D C6 07 90 mov byte ptr [edi], 90h ; [401237] = 90h (nop) 00401130 47 inc edi 00401131 C6 07 90 mov byte ptr [edi], 90h ; [401238] = 90h (nop) 00401134 47 inc edi 00401135 8B 55 08 mov edx, [ebp+arg_0] ; pointer to name (n) 00401138 BB 33 00 00 00 mov ebx, 33h ; loop counter 0040113D 8A 27 mov ah, [edi] ; loop start 0040113F 8A 02 mov al, [edx] ; n[i] 00401141 32 E0 xor ah, al ; c[i] xor n[i] 00401143 88 27 mov [edi], ah ; c[i] = c[i] xor n[i] 00401145 47 inc edi 00401146 42 inc edx 00401147 85 DB test ebx, ebx 00401149 74 0B jz short loc_401156 0040114B 4B dec ebx 0040114C 80 3A 00 cmp byte ptr [edx], 0 0040114F 75 EC jnz short loc_40113D ; loop end 00401151 8B 55 08 mov edx, [ebp+arg_0] 00401154 EB E7 jmp short loc_40113D 00401156 58 pop eax 00401157 5F pop edi 00401158 5A pop edx 00401159 8D 55 F8 lea edx, [ebp+var_8] 0040115C 52 push edx 0040115D 6A 10 push 10h 0040115F 6A 33 push 33h 00401161 FF 75 FC push [ebp+var_4] 00401164 E8 19 8D 00 00 call j_VirtualProtect 00401169 5F pop edi 0040116A 5B pop ebx 0040116B 59 pop ecx 0040116C 59 pop ecx 0040116D 5D pop ebp 0040116E C3 retn He, what's this! The crackme decrypts part of itself at address 401237. It xors our name with the code there - seems that we have to type in a unlock code first and then press Ctrl-Alt-Q to enable our button and to decrypt a part of the code. Let's have a look at the serial algo first. In the listing we search for another occurence of GetDlgItemTextA, there are only two: 004011DD 55 push ebp 004011DE 8B EC mov ebp, esp 004011E0 51 push ecx 004011E1 53 push ebx 004011E2 56 push esi 004011E3 57 push edi 004011E4 33 DB xor ebx, ebx 004011E6 C7 45 FC B9 10 0F+ mov dword ptr [ebp-4], 0F10B9h 004011ED BF 3B 12 40 00 mov edi, offset loc_40123B 004011F2 80 3F 8A cmp byte ptr [edi], 8Ah ; [40123B] == 8Ah ? 004011F5 0F 85 7E 00 00 00 jnz loc_401279 004011FB 6A 65 push 65h 004011FD FF 75 08 push dword ptr [ebp+8] 00401200 E8 A7 8C 00 00 call j_GetDlgItem 00401205 50 push eax 00401206 E8 B3 8C 00 00 call j_GetWindowTextLengthA 0040120B 8B F8 mov edi, eax 0040120D 8D 47 01 lea eax, [edi+1] 00401210 50 push eax 00401211 6A 40 push 40h 00401213 E8 F8 8B 00 00 call j_GlobalAlloc 00401218 8B F0 mov esi, eax 0040121A 47 inc edi 0040121B 57 push edi 0040121C 56 push esi 0040121D 6A 65 push 65h 0040121F FF 75 08 push dword ptr [ebp+8] 00401222 E8 91 8C 00 00 call j_GetDlgItemTextA ; get name 00401227 6A 00 push 0 00401229 6A 00 push 0 0040122B 6A 66 push 66h 0040122D FF 75 08 push dword ptr [ebp+8] 00401230 E8 7D 8C 00 00 call j_GetDlgItemInt ; get serial 00401235 8B F8 mov edi, eax 00401237 EB 3D jmp short near ptr loc_401272+4 ; will be nop nop (see above) 00401239 A4 movsb ; this code is being decrypted 0040123A 5A pop edx 0040123B EF out dx, eax 0040123C 6A 3E push 3Eh 0040123E 67 34 3E db 67h 0040123E xor al, 3Eh 00401241 45 inc ebp 00401242 7A DA jp short near ptr loc_40121D+1 00401244 B5 4E mov ch, 4Eh 00401246 25 99 EE 5C 4B and eax, 4B5CEE99h 0040124B 71 20 jno short near ptr loc_401269+4 0040124D 30 7B 6B xor [ebx+6Bh], bh 00401250 DB 03 fild dword ptr [ebx] 00401252 6E outsb 00401253 64 E5 65 segfs 00401253 in eax, 65h 00401256 A9 E9 D7 BD FC test eax, 0FCBDD7E9h 0040125B 21 99 24 3D 99 21 and [ecx+21993D24h], ebx 00401261 A9 18 8C 63 C4 test eax, 0C4638C18h 00401266 49 dec ecx 00401267 7A 65 jp short near ptr loc_4012CB+3 00401269 3A A0 66 91 3B 7D cmp ah, [eax+7D3B9166h] 0040126F FC cld 00401270 75 07 jnz short loc_401279 00401272 C6 05 EC A0 40 00+ mov byte_40A0EC, 1 ; set flag 00401279 5F pop edi 0040127A 5E pop esi 0040127B 5B pop ebx 0040127C 59 pop ecx 0040127D 5D pop ebp 0040127E C3 retn The byte at address 40123B must be 8Ah. After that check the crackme reads our name and serial and executes the decrypted code. At address 401272 it sets a flag. The flag is being tested in the maincode after the return: 0040135D C6 05 EC A0 40 00+ mov byte_40A0EC, 0 ; clear flag 00401364 56 push esi 00401365 53 push ebx 00401366 E8 72 FE FF FF call loc_4011DD ; see call above 0040136B 83 C4 08 add esp, 8 0040136E 0F BE 15 EC A0 40+ movsx edx, byte_40A0EC ; flag 00401375 4A dec edx 00401376 75 1C jnz short loc_401394 ; flag - 1 == 0 ? 00401378 BE EE A0 40 00 mov esi, offset aErrorlevel1 ; "Errorlevel1!" 0040137D 56 push esi 0040137E E8 1F FE FF FF call sub_4011A2 ; string "Errorlevel1!" --> "Registered !" 00401383 59 pop ecx 00401384 6A 00 push 0 00401386 68 FB A0 40 00 push offset aMessage ; "Message" 0040138B 56 push esi 0040138C 53 push ebx 0040138D E8 32 8B 00 00 call j_MessageBoxA ; BINGO 00401392 EB 2D jmp short loc_4013C1 What we know about the unlock code (u): * sum (n[i] sar 1) = 20Ah * u[2] xor EFh = 8Ah --> u[2] = 65h * to set the flag we have to jump to address 401272 The opcode reference tells us, that "mov r8, r8" begins with 8Ah. That's what we need for the third byte. We could do the following: 401239: A4 5A --> 8A C3 mov al, bl ; dummy code (same as below to make things easier) 40123B: EF 6A --> 8A C3 mov al, bl ; dummy code, byte [40123B] must be 8Ah! 40123D: 3E 67 --> EB 33 jmp 401272 ; jump to location where flag is being set Now we can calculate the first part of our unlock code: u[0]: A4 xor 8A = 2E u[1]: 5A xor C3 = 99 u[2]: EF xor 8A = 65 u[3]: 6A xor C3 = A9 u[4]: 3E xor EB = D5 u[5]: 67 xor 33 = 54 When we trace in softice we see that this unlock code adds to zero. We have to add some more characters to get our sum of 20Ah. The decrypted code doesn't matter because of the jump. I played a bit with my calculator: u[6]..u[23] = 3A Unlock: .™e©ÕT:::::::::::::::::: ********************************* a) start crackme b) type in unlock Code c) press Ctrl-Alt-Q d) type in name and any serial e) press register button f) REGISTERED! Strange things happen to our keyboard while playing with this crackme and my unlock code. Maybe my solution wasn't what detten had in mind - anyway, it works fine and you don't even need a keygen! figugegl